#include"ntp.h"

void creat_udp_sockaddr(struct sockaddr_in * addr, const char* ipStr) {
    addr->sin_family = AF_INET;
    addr->sin_port = htons(NTP_PORT_SERVER);
    addr->sin_addr = *(struct in_addr *)ipStr;
}


struct tm* ntp_get_time(const char* server) {
    printf("ntp : trying to get time from:%s\n", server);

//创建socket
    int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    if (sockfd < 0) {
        printf("ntp : create socket error\n");
        return NULL;
    }

//解析ip地址
    struct hostent * hostInfo = gethostbyname(server); 

    if (!hostInfo) {
        printf("ntp : resolve host name failed\n");
        goto failed;
    }

    char ipStr[INET_ADDRSTRLEN];
    printf("ntp : resolve host name succed,server ip is:%s\n", inet_ntop(hostInfo->h_addrtype, hostInfo->h_addr_list[0], ipStr, sizeof(ipStr)));

//构造数据包
    struct sockaddr_in* addr = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in)) ;
    creat_udp_sockaddr(addr, hostInfo->h_addr_list[0]);
    if (connect(sockfd, (struct sockaddr *)addr ,sizeof(struct sockaddr_in)) < 0) {
        printf("ntp : connect failed\n");
        goto failed;
    }
    printf("ntp : connect success\n");

//设置接收超时时间
    struct timeval tRetry;
    tRetry.tv_sec = NTP_RESEND_TIME_S;
    tRetry.tv_usec = 0;
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tRetry, sizeof(struct timeval));

    ntp_pkt_t pkt;
    int retryNum = 0;
//超时重传数据包
    while(1){
    //构造发送数据包
        memset(&pkt, 0, sizeof(ntp_pkt_t));
        pkt.LI_VN_Mode = NTP_MODE | (NTP_VERSION << 3);

    //发送数据包
        if(send(sockfd, (const void *)&pkt, sizeof(ntp_pkt_t), 0) < 0) {
            printf("ntp : send failed\n");
            goto failed;
        }

    //接收服务端返回的数据包
        memset(&pkt, 0, sizeof(ntp_pkt_t));
        if(recv(sockfd, (void *)&pkt, sizeof(ntp_pkt_t), 0) < 0) {
            printf("timeout retrying...\n");
            retryNum++;
            if(retryNum == NTP_RESEND_MAX_NUM) goto failed;
            continue;
        } 
        break;
    }


//处理解析服务端数据包
    pkt.trans_ts.seconds = htonl(pkt.trans_ts.seconds);
    close(sockfd);
    time_t t = pkt.trans_ts.seconds - NTP_TIME_1900_1970;
    return localtime(&t);

failed:
    close(sockfd);
    return NULL;
}